#include <assert.h>
#include <iostream>

#include "citizen.hpp"
#include "city.hpp"
#include "filesystem.hpp"
#include "foreach.hpp"
#include "game_logic.hpp"
#include "government.hpp"
#include "terrain.hpp"
#include "tile.hpp"
#include "tile_logic.hpp"
#include "unit.hpp"
#include "unit_type.hpp"
#include "wml_node.hpp"
#include "wml_parser.hpp"
#include "world.hpp"
#include "world_generator.hpp"

namespace {
void do_world_turn(world& w)
{
	begin_turn(w);
	w.calculate_trades();
	migrations_list migrations;
	end_turn(w, w.map(), migrations);
}

int evaluate_tile_as_starting_pos(world& w, const hex::location& loc)
{
	hex::const_tile_ptr t = w.map().get_tile(loc);
	if(t->terrain()->move_cost() < 0) {
		return -1;
	}

	int score = 0;
	hex::location adj[6];
	get_adjacent_tiles(loc, adj);
	for(int n = 0; n != 6; ++n) {
		if(!w.map().is_loc_on_map(adj[n])) {
			continue;
		}
		hex::const_tile_ptr t = w.map().get_tile(adj[n]);
		score += t->citizens().size();
	}

	return score;
}

void convert_citizens(world& w, government_ptr allegiance, const hex::location& loc)
{
	hex::location adj[7];
	adj[0] = loc;
	get_adjacent_tiles(loc, &adj[1]);
	foreach(const hex::location& loc, adj) {
		if(!w.map().is_loc_on_map(loc)) {
			continue;
		}
		hex::tile_ptr t = w.map().get_tile(loc);
		foreach(citizen_ptr c, t->citizens()) {
			c->set_allegiance(allegiance);
		}
	}
}

}

world* generate_world()
{
	world* w = new world(wml::parse_wml(sys::read_file("map_generator.cfg")));
	for(int x = 0; x != w->map().width(); ++x) {
		for(int y = 0; y != w->map().height(); ++y) {
			foreach(citizen_ptr c, w->map().get_tile(hex::location(x,y))->citizens()) {
				c->get_item("silver", 10);
			}
		}
	}

	for(int i = 0; i != 4; ++i) {
		do_world_turn(*w);
		int ncitizens = 0;
		foreach(const hex::tile_ptr& t, w->map().tiles()) {
			ncitizens += t->citizens().size();
		}
		std::cerr << "TURN " << i << " CENSUS: " << ncitizens << "\n";
	}

	hex::location best_tile;
	int best_score = -1;
	for(int x = 0; x != w->map().width(); ++x) {
		for(int y = 0; y != w->map().height(); ++y) {
			hex::location loc(x,y);
			const int score = evaluate_tile_as_starting_pos(*w, loc);
			if(score > best_score) {
				best_score = score;
				best_tile = loc;
			}
		}
	}

	assert(best_tile.valid());

	w->add_unit(best_tile, unit_ptr(new unit(unit_type::get("settler"), w->sides().front(), city_ptr(), citizen_ptr(new citizen))));
	convert_citizens(*w, w->sides().front(), best_tile);
	
	return w;
}
